package com.core.sdk.task;

import java.io.Serializable;
import java.util.HashMap;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

import com.core.sdk.core.LogUtil;
import com.core.sdk.core.MessageSendListener;

import android.os.Process;

public abstract class Task implements Serializable {

	private static final long serialVersionUID = 1L;

	protected final String tag = this.getClass().getSimpleName();

	private final String lock = new String("TASKLOCK");

	private String id = null;

	private volatile Status mStatus = Status.PENDING;

	private transient WorkerRunnable<Object> mWorker = null;

	private transient FutureTask<Object> mFuture = null;

	private transient OnStateChangeListener listener = null;

	private HashMap<String, Serializable> params = null;

	private int flags = 0;

	/** 当前是第几次重试 ，但这次还没有执行 */
	private volatile int currentRetryCount = 0;

	private volatile int maxRetryCount = 0;
	
	private transient MessageSendListener sender = null;

	protected abstract Object doInBackground() throws Exception;

	private Task getThis() {
		return this;
	}

	public boolean isNotTimely() {
		return (getFlags() & FLAG_TIMELY) == 0 && (getFlags() & FLAG_TIMELY_POOL) == 0;
	}

	public Task() {
		initFuture();
	}

	private void initWorker() {
		mWorker = new WorkerRunnable<Object>() {
			@Override
			public Object call() throws Exception {
				if (getStatus() != Status.PENDING) {
					setStatus(Status.PENDING);
				}
				Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
				setStatus(Status.RUNNING);
				// (1) 重试次数为<=0的
				if (getMaxRetryCount() <= 0) {
					return doInBackground();
				}
				if (getCurrentRetryCount() > getMaxRetryCount()) {
					throw new Exception("Has been reached maxRetryCount:" + getMaxRetryCount());
				}
				// (2)重试次数大于0的，首先先把自己的那一次先执行了来，然后再看是否需要重试
				Object obj = null;
				boolean needRetry = false;
				Exception firstThrowable = null;
				try {
					obj = doInBackground();
				} catch (Exception e) {
					firstThrowable = e;
					needRetry = true;
				}
				if (!needRetry)
					return obj;
				final int maxRetryCount = getThis().getMaxRetryCount();
				if (isNotTimely()) { // 持久化任务
					LogUtil.e(tag, "taskId:" + getId() + " retry " + getCurrentRetryCount() + " failed");
					setCurrentRetryCount(getCurrentRetryCount() + 1);
					throw firstThrowable;
				}
				// 临时性任务
				int retryCount = 0;
				while (retryCount < maxRetryCount) {
					try {
						Thread.sleep(10L);
						retryCount++;
						obj = doInBackground();
						LogUtil.e(tag, "taskId:" + getId() + " retry " + retryCount + " sucessed");
						break;
					} catch (Exception e) {
						LogUtil.e(tag, "taskId:" + getId() + " retry " + retryCount + " failed");
						getThis().setCurrentRetryCount(retryCount);
						if (retryCount == maxRetryCount) {
							throw new Exception("Has been reached maxRetryCount:" + maxRetryCount, e);
						}
					}
				}
				return obj;
			}
		};
	}

	private void initFuture() {
		if (mWorker == null) {
			initWorker();
		}
		mFuture = new FutureTask<Object>(mWorker) {
			@Override
			protected void done() {
				Object result = null;
				try {
					result = get();
				} catch (InterruptedException e) {
					android.util.Log.w(tag, e);
				} catch (ExecutionException e) {
					setStatus(Status.ERROR_STOPED);
					listener.onError(e, getThis());
					return;
				} catch (CancellationException e) {
					setMaxRetryCount(0);
					setStatus(Status.CANCELED);
					listener.onCanceled(getThis());
					return;
				} catch (Throwable t) {
					setStatus(Status.ERROR_STOPED);
					listener.onError(t, getThis());
					return;
				}

				setStatus(Status.FINISHED);
				listener.onSuccess(result, getThis());
			}
		};
	}

	public void destoryFuture() {
		this.mFuture = null;
	}

	public final boolean isCancelled() {
		return mFuture.isCancelled();
	}

	public final boolean cancel(boolean mayInterruptIfRunning) {
		boolean canceled = mFuture.cancel(mayInterruptIfRunning);
//		Thread.currentThread().stop();
		return canceled;
	}

	protected final void setProgress(Progress progress) {
		this.listener.onProgressUpdate(progress, this);
	}

	public enum Status {
		PENDING, RUNNING, ERROR_STOPED, CANCELED, FINISHED
	}

	// flags
	public static final int FLAG_AUTO_DELETE = 1 << 1;
	public static final int FLAG_TIMELY = 1 << 2;
	public static final int FLAG_VISIBLE = 1 << 3;
	public static final int FLAG_TIMELY_POOL = 1 << 4;

	public interface OnStateChangeListener {
		
		void onSuccess(Object result, Task t);

		void onError(Throwable e, Task t);

		void onProgressUpdate(Progress progress, Task t);

		void onCanceled(Task t);

		void onStatusChanged(Task t, Status newStatus, Status oldStatus);
	}

	private abstract class WorkerRunnable<T> implements Callable<T> {
	}

	public static class Progress {
		private int total;
		private int current;
		private int scale;

		public int getTotal() {
			return total;
		}

		public void setTotal(int total) {
			this.total = total;
		}

		public int getCurrent() {
			return current;
		}

		public void setCurrent(int current) {
			this.current = current;
		}

		public int getScale() {
			return scale;
		}

		public void setScale(int scale) {
			this.scale = scale;
		}
	}

	public String getId() {
		return this.id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public FutureTask<Object> getFuture() {
		if (this.mFuture == null)
			initFuture();
		return this.mFuture;
	}

	public final Status getStatus() {
		return mStatus;
	}

	public int getFlags() {
		return flags;
	}

	public void setFlags(int flags) {
		this.flags = flags;
	}

	public void setOnStateChangeListener(OnStateChangeListener oscl) {
		this.listener = oscl;
	}

	public void setParams(HashMap<String, Serializable> params) {
		this.params = params;
	}

	protected HashMap<String, Serializable> getParams() {
		return this.params;
	}

	public int getCurrentRetryCount() {
		synchronized (lock) {
			return currentRetryCount;
		}
	}

	public void setCurrentRetryCount(int currentRetryCount) {
		synchronized (lock) {
			this.currentRetryCount = currentRetryCount;
		}
	}

	public int getMaxRetryCount() {
		return maxRetryCount;
	}

	public void setMaxRetryCount(int maxRetryCount) {
		this.maxRetryCount = maxRetryCount;
	}

	private void setStatus(Status mStatus) {
		Status oldStatus = this.mStatus;
		this.mStatus = mStatus;
		if (this.mStatus != oldStatus) {
			listener.onStatusChanged(this, this.mStatus, oldStatus);
		}
	}

	public void setSender(MessageSendListener sender) {
		this.sender = sender;
	}
	public MessageSendListener getSender() {
		return sender;
	}
	
}
